package cn.xinfei.xdecision.common.service.component;

import cn.xinfei.xdecision.common.model.common.PageResultNew;
import cn.xinfei.xdecision.common.model.common.ResponseEntityBuilder;
import cn.xinfei.xdecision.common.model.common.ResponseEntityDto;
import cn.xinfei.xdecision.common.model.component.ComponentVersionVo;
import cn.xinfei.xdecision.common.model.component.ComponentVo;
import cn.xinfei.xdecision.common.model.component.IgnoredParamCheck;
import cn.xinfei.xdecision.common.model.component.dependency.resp.DecisionComponentDependencyResp;
import cn.xinfei.xdecision.common.model.component.guiderule.vo.RuleListReqVo;
import cn.xinfei.xdecision.common.model.login.SessionManager;
import cn.xinfei.xdecision.common.service.common.sso.SSOService;
import cn.xinfei.xdecision.common.service.common.sso.dto.SSOUserInfoReqDto;
import cn.xinfei.xdecision.common.service.common.sso.dto.SSOUserInfoRespDto;
import cn.xinfei.xdecision.common.utils.constant.SysConstant;
import cn.xinfei.xdecision.common.utils.enums.enginex.ComponentVersionStatusEnum;
import cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum;
import cn.xinfei.xdecision.common.utils.util.FutureUtils;
import com.github.pagehelper.page.PageMethod;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * 组件中心整合类，对外服务类
 *
 * @author Zdy
 * @since 2023-03-31
 */
@Component
@Slf4j
public class ComponentCommonContext {

    @Resource
    private List<ComponentCommonService> componentCommonServices;

    @Resource(name = "bizProcessorThreadPool")
    private ExecutorService bizProcessorThreadPool;

    @Resource
    private SSOService ssoService;

    /**
     * 查询变量的依赖关系
     */
    public List<DecisionComponentDependencyResp> getDependencyByVarCodes(List<String> varCodes) {
        if (CollectionUtils.isEmpty(varCodes)) {
            return new ArrayList<>();
        }
        List<DecisionComponentDependencyResp> list = new CopyOnWriteArrayList<>();
        componentCommonServices.forEach(service -> list.addAll(service.getComponentCodeByVarCodes(varCodes)));
        return list;
    }

    /**
     * 查询变量被引用的组件
     */
    public List<DecisionComponentDependencyResp> getComponentCodeByVarCodes(List<String> componentCode) {
        if (CollectionUtils.isEmpty(componentCode)) {
            return new ArrayList<>();
        }
        List<DecisionComponentDependencyResp> list = new CopyOnWriteArrayList<>();
        List<Future<Void>> allFutureList = Lists.newArrayList();
        componentCommonServices.forEach(service -> allFutureList.add(CompletableFuture.runAsync(() ->
                list.addAll(service.getComponentCodeByVarCodes(componentCode)), bizProcessorThreadPool)));
        allFutureList.forEach(x -> FutureUtils.futureGet(x, ErrorCodeEnum.SEARCH_ERROR.getCode(),
                ErrorCodeEnum.SEARCH_ERROR.getMessage()));
        return list;
    }

    /**
     * 查询决策流中组件中心的列表（只能展示锁定状态的列表）
     */
    public ResponseEntityDto<PageResultNew<ComponentVo>> pageComponentInfoByCon(RuleListReqVo ruleListReqVo) {
        ComponentCommonService targetComponent = ComponentCommonService.getTargetComponentByType(ruleListReqVo.getComponentType());
        if (Objects.isNull(targetComponent)) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.COMPONENT_TYPE_ERROR);
        }
        PageMethod.startPage(ruleListReqVo.getPageNum(), ruleListReqVo.getPageSize());
        //组件中心自行实现
        ruleListReqVo.setOrgIdList(SessionManager.getLoginAccount().getOrgIdList());
        List<ComponentVo> componentVos = targetComponent.listComponentInfoByCon(ruleListReqVo);
        SSOUserInfoReqDto ssoUserInfoReqDto = new SSOUserInfoReqDto();
        Set<Long> ids = new HashSet<>();
        componentVos.forEach(x -> {
            ids.add(x.getCreateUserId());
            ids.add(x.getUpdateUserId());
        });
        ssoUserInfoReqDto.setId(new ArrayList<>(ids));
        Map<Long, String> sysMap = ssoService.getUserInfos(ssoUserInfoReqDto).stream()
                .collect(Collectors.toMap(SSOUserInfoRespDto::getId, SSOUserInfoRespDto::getName));
        componentVos.forEach(x -> {
            x.setCreateName(sysMap.getOrDefault(x.getCreateUserId(), StringUtils.EMPTY));
            x.setUpdateUserName(sysMap.getOrDefault(x.getUpdateUserId(), StringUtils.EMPTY));
        });
        if (CollectionUtils.isEmpty(componentVos)) {
            return PageResultNew.success(new ArrayList<>());
        }
        return PageResultNew.success(componentVos);
    }

    public static void swapVersionNoDesc(List<ComponentVersionVo> componentVersionVos) {
        componentVersionVos.forEach(componentVersionVo ->
                componentVersionVo.setVersionNoDesc("V" + componentVersionVo.getVersionNo())
                        .setStatusDesc(Objects.requireNonNull(
                                ComponentVersionStatusEnum.get(componentVersionVo.getStatus())).getName()));
    }

    /**
     * 判断对象属性是否全部有值
     *
     * @param object        入参
     * @param emptyFieldSet 空列
     */
    public static void checkParamNotEmpty(Object object, Set<String> emptyFieldSet) {
        // 得到类对象
        Class<?> clazz = object.getClass();
        // 得到所有属性
        List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));

        //向上循环 遍历父类属性
        while (clazz != Object.class) {
            clazz = clazz.getSuperclass();
            fields.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
        }

        for (Field field : fields) {
            try {
                //过滤忽略字段
                if (Objects.nonNull(field.getAnnotation(IgnoredParamCheck.class))) {
                    continue;
                }
                ReflectionUtils.makeAccessible(field);
                //得到属性值
                Object fieldValue = field.get(object);
                //得到属性类型
                Type fieldType = field.getType();
                String fieldName = field.getName();
                if (Objects.isNull(fieldValue)) {
                    emptyFieldSet.add(fieldName);
                } else {
                    if (Objects.equals(fieldType, String.class) &&
                            StringUtils.isEmpty((CharSequence) fieldValue)) {
                        emptyFieldSet.add(fieldName);
                    } else if (Objects.equals(fieldType, Integer.class) &&
                            Objects.equals(fieldValue, SysConstant.ZERO.intValue())) {
                        emptyFieldSet.add(fieldName);
                    } else if (Objects.equals(fieldType, Long.class) &&
                            Objects.equals(fieldValue, SysConstant.ZERO)) {
                        emptyFieldSet.add(fieldName);
                    } else if (Objects.equals(fieldType, Double.class) &&
                            Objects.equals(fieldValue, Double.parseDouble(SysConstant.ZERO.toString()))) {
                        emptyFieldSet.add(fieldName);
                    } else if (List.class.isAssignableFrom((Class<?>) fieldType)) {
                        Class<?> listClazz = fieldValue.getClass();
                        //反射调用获取到list的size方法来获取到集合的大小
                        Method sizeMethod = listClazz.getDeclaredMethod("size");
                        //集合长度
                        int size = (int) sizeMethod.invoke(fieldValue);
                        //孩子可以为空,自定义输出表可以为空
                        if (!Objects.equals(fieldName, "children")
                                && !Objects.equals(fieldName, "strategyOutputList")
                                && !Objects.equals(fieldName, "failOutputList")
                                && size == 0) {
                            emptyFieldSet.add(fieldName);
                        } else if (size > 0) {
                            //递归
                            List<Object> list = (List<Object>) fieldValue;
                            list.forEach(x -> checkParamNotEmpty(x, emptyFieldSet));
                        }
                    }
                }
            } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                log.error("取值错误", e);
            }
        }
    }
}
